#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "misc.h"
#include "txt.h"
#include "gen_read.h"

TXT *txt_init(void)
{
  TXT *txt;
  TXTBLK *tb;
  if (!(txt = malloc(sizeof(TXT)))) {
    return NULL;
  }
  if (!(tb = malloc(sizeof(TXTBLK)))) {
    free(txt);
    return NULL;
  }
  txt->chidx = 0;
  txt->head = txt->end = tb;
  tb->next = NULL;
  return txt;
}

void txt_free(TXT *txt)
{
  TXTBLK *tb, *tb_prev;
  if (txt) {
    tb = txt->head;
    do {
      // do .. while is okay since there is always at least one
      // TXTBLK in the list.
      tb_prev = tb;
      tb = tb->next;
      free(tb_prev);
    } while (tb);
    free(txt);
  }
  return;
}

int txt_append_char(TXT *txt, char c)
{
  if (!txt) {
    return 0;
  }
  if (txt->chidx >= TXT_CHUNK_SIZE) {
    TXTBLK *tb;
    if (!(tb = malloc(sizeof(TXTBLK)))) {
      return 0;
    }
    txt->end->next = tb;
    txt->end->next->next = NULL;
    txt->end = tb;
    txt->chidx = 0;
  }
  txt->end->str[txt->chidx++] = c;
  return 1;
}

int txt_nchars(TXT *txt)
{
  int n = 0;
  TXTBLK *tb;
  for (tb = txt->head; tb; tb = tb->next) {
    n += tb == txt->end ? txt->chidx : TXT_CHUNK_SIZE;
  }
  return n;
}

char *txt_to_str(TXT *txt)
{
  int n = txt_nchars(txt) + 1, size;
  char *s, *sp;
  TXTBLK *tb;
  if (!(s = malloc(n))) {
    return NULL;
  }
  sp = s;
  for (tb = txt->head; tb; tb = tb->next) {
    size = tb == txt->end ? txt->chidx : TXT_CHUNK_SIZE;
    memcpy(sp, tb->str, size);
    sp += size;
  }
  *sp = '\0';
  return s;
}

#ifdef TEST_TXT

void main(int argc, char **argv)
{
  GEN_READ r;
  TXT *t;
  char c, *s;
  if (!(t = txt_init())) {
    printf("unable to create a TXT\n");
    exit(0);
  }
  if (gr_open_rdln(&r, ">: ")) {
    while (gr_get_char(&r, &c)) {
      if (!txt_append_char(t, c)) {
	printf("unable to append character\n");
	exit(0);
      }
    }
    printf("number of characters appended: %d\n", txt_nchars(t));
    if (!(s = txt_to_str(t))) {
      printf("uable to convert to C-style string\n");
      exit(0);
    }
    printf("str=[%s]\n", s);
    free(s);
  }
  txt_free(t);
}

#endif
